package com.mxchip.livestar.repository

import android.content.Context
import android.os.Looper
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.mxchip.livestar.utils.FileLog
import com.mxchip.livestar.rx.RxBus
import com.mxchip.livestar.rx.RxConstant
import com.videohigh.graham.*
import java.text.SimpleDateFormat
import java.util.*

/**
 * 上层调用信令接口
 */
object RoomClientRepository {

    private const val TAG = "RoomClientRepository"

    private val sampleSDK = SampleSDK.getInstance()

    private val logger = FileLog.getLogger(RoomClientRepository::class.java)

    private val stateLiveData = MutableLiveData<Boolean>(true)

    val isConnect: LiveData<Boolean>
        get() = stateLiveData

    private val mMyTerm = MutableLiveData<Term>()
    private val mJoinedMicUserIds = MutableLiveData<List<TermAudioDevice>>(arrayListOf())
    private val mIsMyselfTheOnlyOneLeft = MutableLiveData<Boolean>(false)
    private val mAvDevices = MutableLiveData<List<TermVideoDevice>>(arrayListOf())
    private val mTermIdsAll = MutableLiveData<Set<Term>>().apply { value = linkedSetOf() }

    val micUserIds: LiveData<List<TermAudioDevice>>
        get() = mJoinedMicUserIds

    val isMyselfTheOnlyOneLeft: LiveData<Boolean>
        get() = mIsMyselfTheOnlyOneLeft

    val avDevices: LiveData<List<TermVideoDevice>>
        get() = mAvDevices

    val termIdsAll: LiveData<Set<Term>>
        get() = mTermIdsAll

    private fun setSessionContext(sessionContext: SessionContext) {
        val myTerm = sessionContext.myTerm
        val terms = sessionContext.callList.plus(sessionContext.inviteList)
        val callType = sessionContext.callType
        val videoDevices = sessionContext.videoDevices
        val audioDevices = sessionContext.audioDevices

        // val termIds = terms.map { it.termId }.toMutableSet()
        val isMyselfTheOnlyOneLeft = (terms.size <= 1 && !callType.equals(SessionContext.CallType.GROUP.name, true))
        // val avDevices = videoDevices.map { AVDevice(it.term.dbyUid, it.deviceName) }


        if (Looper.myLooper() == Looper.getMainLooper()) {
            mMyTerm.value = myTerm
            mAvDevices.value = videoDevices
            mJoinedMicUserIds.value = audioDevices
            mTermIdsAll.value = terms
            mIsMyselfTheOnlyOneLeft.value = isMyselfTheOnlyOneLeft
        }
        else {
            mMyTerm.postValue(myTerm)
            mAvDevices.postValue(videoDevices)
            mJoinedMicUserIds.postValue(audioDevices)
            mTermIdsAll.postValue(terms)
            mIsMyselfTheOnlyOneLeft.postValue(isMyselfTheOnlyOneLeft)
        }
    }

    private val dataEventListener  = object: SDKDataEventListener {

        override fun onVideoDeviceChanged(sessionContext: SessionContext) {
            Log.e(TAG, SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onVideoDeviceChanged result:" + sessionContext)
            setSessionContext(sessionContext)
            RxBus.get().post(RxConstant.VIDEO_DEVICE_EVENT, sessionContext)
        }

        override fun onAudioDeviceChanged(sessionContext: SessionContext) {
            Log.e(TAG, SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onAudioDeviceChanged result:" + sessionContext)

            setSessionContext(sessionContext)
        }

        override fun onShareContentAdd(sessionContext: SessionContext) {
            Log.e(TAG, SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onShareContentAdd result:" + sessionContext)
            logger.info(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onShareContentAdd result:" + sessionContext)
            setSessionContext(sessionContext)
            RxBus.get().post(RxConstant.SHARE_CONTENT_ADD_EVENT, sessionContext)
        }

        override fun onShareContentRemove(sessionContext: SessionContext) {
            Log.e(TAG, SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onShareContentRemove result:" + sessionContext)
            logger.info(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onShareContentRemove result:" + sessionContext)
            setSessionContext(sessionContext)
            RxBus.get().post(RxConstant.SHARE_CONTENT_REMOVE_EVENT, sessionContext)
        }

        override fun onCallIn(sessionContext: SessionContext) {
            Log.e(TAG, SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onCallIn result:" + sessionContext)
            RxBus.get().post(RxConstant.CALL_IN_EVENT, sessionContext)
        }

        override fun onInvited(sessionContext: SessionContext) {
            Log.e(TAG, SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onInvited result:" + sessionContext)
            logger.info(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onInvited result:" + sessionContext)
            setSessionContext(sessionContext)
            RxBus.get().post(RxConstant.INVITATED_EVENT, sessionContext)
        }

        override fun onLeaveCall(sessionContext: SessionContext) {
            Log.e(TAG, SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onLeaveCall result:" + sessionContext)
            logger.info(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onLeaveCall result:" + sessionContext)
            setSessionContext(sessionContext)
            RxBus.get().post(RxConstant.LEAVE_CALL_EVENT, sessionContext)
        }

        override fun onEnterCall(sessionContext: SessionContext) {
            Log.e(TAG, SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " onEnterCall result:" + sessionContext)
            setSessionContext(sessionContext)
            RxBus.get().post(RxConstant.ENTER_EVENT, sessionContext)
        }


        override fun onConnect() {
            stateLiveData.postValue(true)
            RxBus.get().post(RxConstant.REGISTER_SUCCESS_NOTIFY_MAIN_ACTIVITY, true)
        }

        override fun onDisconnect() {
            Log.e(TAG, "onDisconnect")
            stateLiveData.postValue(false)
            RxBus.get().post(RxConstant.DISCONNECT, true)
        }

        override fun onDisconnectReason(event: String?) {
            RxBus.get().post(RxConstant.DISCONNECT_REASON, event ?: " empty string")
        }

        override fun onReConnectError() {
            Log.e(TAG, "onReConnectError")
            stateLiveData.postValue(false)
        }

        override fun onReConnect() {
            RxBus.get().post(RxConstant.RECONNECT, true)
        }

        override fun onError(code: Int, message: String) {
            Log.e(TAG, "SDKSample onError: $code $message")
        }

    }

    /**
     * 设置日志回调
     * */
    fun setLogEventListener(listener: LogEventListener?) {
        sampleSDK.setLogEventListener(listener)
    }

    /**
     * 连接
     */
    fun connect() {
        sampleSDK.connect()
    }

    /**
     *  断开
     */
    fun disconnect() {
        sampleSDK.disconnect()
    }

    /**
     * 检查连接状态
     */
    fun connected(): Boolean {
        return sampleSDK.isConnected//socketClient.connected()
    }

    /**
     * 挂断请求
     */
    fun endCall(callback: SDKCallback<Void>) {
        sampleSDK.endCall(callback)
    }

    /**
     * 发起对话
     */
    fun makeCall(groupId: String?, termIds: Array<String>, callback: SDKCallback<SessionContext>, failureCallback: SDKFailureCallback) {
        sampleSDK.makeCall(groupId, termIds, {
            setSessionContext(it)
            callback.onSuccess(it)
        }, failureCallback)
    }

    /**
     * 通话中邀请
     */
    fun invite(termIds: Array<String>, callback: SDKCallback<SessionContext>, failureCallback: SDKFailureCallback) {
        sampleSDK.invite(termIds, {
            setSessionContext(it)
            callback.onSuccess(it)
        }, failureCallback)
    }

    /**
     * 开启屏幕共享
     */
    fun addShareContent(deviceName: String, callback: SDKCallback<Void>, failureCallback: SDKFailureCallback) {
        sampleSDK.addShareContent(deviceName, callback, failureCallback)
    }
    /**
     * 关闭屏幕共享
     */
    fun removeShareContent(deviceName: String, callback: SDKCallback<Void>, failureCallback: SDKFailureCallback) {
        sampleSDK.removeShareContent(deviceName, callback, failureCallback)
    }


    /**
     * 打开camera
     */
    fun addVideoDevice(deviceNames: Array<String>, callback: SDKCallback<Void>, failureCallback: SDKFailureCallback) {
        sampleSDK.addVideoDevice(deviceNames, callback, failureCallback)
    }



    /**
     * 关闭camera
     */
    fun removeVideoDevice(deviceNames: Array<String>, callback: SDKCallback<Void>, failureCallback: SDKFailureCallback) {
        sampleSDK.removeVideoDevice(deviceNames, callback, failureCallback)
    }

    /**
     * 加入通话
     */
    fun enterCall(callback: SDKCallback<SessionContext>?, failureCallback: SDKFailureCallback?) {
        // Log.e(TAG, "syncChannel: $roomId $channelId $callIndex ${connected()}")

        if (connected()) {
            sampleSDK.enterCall( { session->
                setSessionContext(session)
                callback?.onSuccess(session)
            }, { code, message ->
                failureCallback?.onFailure(code, message)
            })
        }
    }

    /**
     * 心跳
     */
    fun keepAliveChannel(callback: SDKCallback<Void>, failureCallback: SDKFailureCallback) {
        sampleSDK.keepAliveChannel(callback, failureCallback)
    }

    /*fun getStates(termNumbers: Array<String>, action: ((GetStatesResp) -> Unit)?) {
        if (connected()) {
            sampleSDK.getStates(termNumbers, { action?.invoke(it) }, { errorCode, message ->

            })
        }
    }*/

    /**
     * 同步其他客户端数据
     */
    fun syncChannel(callback: SDKCallback<SessionContext>, failureCallback: SDKFailureCallback) {
        sampleSDK.syncChannel({
            setSessionContext(it)
            callback.onSuccess(it)
        }, failureCallback)
    }




    /**
     * 同步数据并保持心跳
     */
    fun syncAndKeepAliveChannel(callback: SDKCallback<SessionContext>?, failureCallback: SDKFailureCallback?) {
        // Log.e(TAG, "syncChannel: $roomId $channelId $callIndex ${connected()}")

        if (connected()) {
            sampleSDK.syncAndKeepAliveChannel( { session->
                setSessionContext(session)
                callback?.onSuccess(session)
            }, { code, message ->
                failureCallback?.onFailure(code, message)
            })
        }
    }



    init {
        sampleSDK.setDataEventListener(dataEventListener)
    }


    fun init(context: Context, settings: Settings) {
        sampleSDK.init(context, settings)
    }

    /**
     * 销毁socket
     */
    fun destroy() {
        sampleSDK.destroy()
    }

    fun clear() {
        val myTerm = null
        val audioDevices = emptyList<TermAudioDevice>()
        val termIds = emptySet<Term>()
        val isMyselfTheOnlyOneLeft = false
        val avDevices = emptyList<TermVideoDevice>()

        if (Looper.myLooper() == Looper.getMainLooper()) {
            mMyTerm.value = myTerm
            mAvDevices.value = avDevices
            mJoinedMicUserIds.value = audioDevices
            mTermIdsAll.value = termIds
            mIsMyselfTheOnlyOneLeft.value = isMyselfTheOnlyOneLeft
        }
        else {
            mMyTerm.postValue(myTerm)
            mAvDevices.postValue(avDevices)
            mJoinedMicUserIds.postValue(audioDevices)
            mTermIdsAll.postValue(termIds)
            mIsMyselfTheOnlyOneLeft.postValue(isMyselfTheOnlyOneLeft)
        }
    }

    /**
     * 登录权限验证
     * */
    fun login(loginCallback: LoginCallback) {
        sampleSDK.login(loginCallback)
    }

    /**
     * 会控消息：移除音频
     * */
    fun mgtMuteAudio(terms: Array<Term>) {
        sampleSDK.mgtMuteAudio(terms)
    }

    /**
     * 会控消息：移除摄像头
     * */
    fun mgtMuteCamera(terms: Array<Term>) {
        sampleSDK.mgtMuteCamera(terms)
    }

    /**
     * 会控消息：移除屏幕共享
     * */
    fun mgtMuteShareContent(terms: Array<Term>) {
        sampleSDK.mgtMuteShareContent(terms)
    }

    /**
     * 获取权限验证信息
     * */
    fun getAuthInfo(callback: SDKCallback<AuthInfo>, failureCallback: SDKFailureCallback) {
        sampleSDK.getAuthInfo(callback, failureCallback)
    }

    /**
     * 发送有音频数据包
     * */
    fun sendAudioDeviceBytes(deviceName: String, data: ByteArray) {
        sampleSDK.sendAudioDeviceBytes(deviceName, data)
    }

    /**
     * 设置远端拉流数据包回调
     * */
    fun setStreamEventListener(sdkStreamEventListener: SDKStreamEventListener?) {
        sampleSDK.setStreamEventListener(sdkStreamEventListener)
    }

    /**
     * 发送视频数据包
     * */
    fun sendVideoDeviceBytes(deviceName: String, data: ByteArray, width: Int, height: Int) {
        sampleSDK.sendVideoDeviceBytes(deviceName, data, width, height)
    }

    /**
     * 关闭远端下行视频拉流
     * */
    fun muteRemoteVideoStream(device: TermVideoDevice, mute: Boolean) {
        sampleSDK.muteRemoteVideoStream(device, mute)
    }

    /**
     * 关闭远端下行音频拉流
     * */
    fun muteRemoteAudioStream(device: TermAudioDevice, mute: Boolean) {
        sampleSDK.muteRemoteAudioStream(device, mute)
    }

    /**
     * 开启本地音频设备
     * */
    fun addAudioDevice(deviceName: String, callback: SDKCallback<Void>, failureCallback: SDKFailureCallback) {
        sampleSDK.addAudioDevice(deviceName, callback, failureCallback)
    }

    /**
     * 关闭本地音频设备
     * */
    fun removeAudioDevice(deviceName: String, callback: SDKCallback<Void>, failureCallback: SDKFailureCallback) {
        sampleSDK.removeAudioDevice(deviceName, callback, failureCallback)
    }

    fun setMgtEventListener(mgtEventListener: SDKMgtEventListener?) {
        sampleSDK.setMgtEventListener(mgtEventListener)
    }

    fun setNetworkQualityListener(networkQualityListener: SDKNetworkQualityListener?) {
        sampleSDK.setNetworkQualityListener(networkQualityListener)
    }

}